package net.posick.ws.soap;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import net.posick.ws.xml.Name;
import net.posick.ws.xml.Namespace;
import net.posick.ws.xml.XmlElement;

/**
 * The SOAPEnvelope class is an implementation of a WS-I Basic Profile 1.2 SOAPEnvelope.
 * 
 * @author Steve Posick
 */
public class SOAPEnvelope extends SOAPBase implements Serializable
{
    private static final long serialVersionUID = 201403271221L;
    
    
    public static final String ELEMENT_NAME = "Envelope";
    
    public static final Name FQN = new Name(new Namespace(PREFIX_SOAP_1_1, NAMESPACE_SOAP_1_1), ELEMENT_NAME);
    
    
    protected SOAPHeader header = null;
    
    protected SOAPBody body = null;
    
    
    public SOAPEnvelope()
    {
        super(FQN);
    }
    
    
    public SOAPEnvelope(SOAPHeader header, SOAPBody body)
    {
        super(FQN);
        this.header = header;
        addChild(header);

        this.body = body;
        addChild(body);
    }
    
    
    public List<XmlElement> getHeaders(Name name)
    {
        List<XmlElement> elements = new ArrayList<XmlElement>();
        
        if (header != null)
        {
            elements.addAll(header.getChildren(name));
        }
        
        return elements;
    }
    
    
    public List<SOAPAction> getSOAPActions()
    {
        List<SOAPAction> elements = new ArrayList<SOAPAction>();
        
        if (header != null)
        {
            List<XmlElement> headerElements = header.getChildren(SOAPAction.FQN);
            for (XmlElement headerElement : headerElements)
            {
                if (headerElement instanceof SOAPAction)
                {
                    elements.add((SOAPAction) headerElement);
                } else
                {
                    try
                    {
                        SOAPAction action = SOAPAction.toSOAPAction(headerElement);
                        elements.add(action);
                        XmlElement.replace(headerElement, action);
                    } catch (SOAPException e)
                    {
                        e.printStackTrace(System.err);
                    }
                }
            }
        }
        
        return elements;
    }


    public SOAPHeader getHeader()
    {
        return header;
    }


    public void setHeaders(SOAPHeader header)
    {
        this.header = header;
    }


    public SOAPBody getBody()
    {
        return body;
    }


    public void setBody(SOAPBody body)
    {
        this.body = body;
    }
    
    
    public static SOAPEnvelope parse(CharSequence xml)
    throws SOAPException
    {
        XmlElement element = null;
        try
        {
            element = XmlElement.parse(xml);
        } catch (Exception e)
        {
            SOAPException.wrap(e);
        }
        
        return SOAPEnvelope.toSOAPEnvelope(element);
    }
    
    
    public static SOAPEnvelope toSOAPEnvelope(XmlElement xml)
    throws SOAPException
    {
        SOAPEnvelope env = new SOAPEnvelope();
        
        Name name = xml.getName();
        
        if (FQN.equals(name))
        {
            List<XmlElement> elements = xml.getChildren();
            if (elements != null && elements.size() > 0)
            {
                for (XmlElement element : elements)
                {
                    if (env.body != null)
                    {
                        throw new SOAPException("Invalid WS-I Basic Profice 1.2 SOAP Envelope \"" + xml.getName() + "\". " + ERROR_MESSAGE_R1011);
                    }
                    
                    Name eName = element.getName();
                    if (!eName.getNamespace().hasPrefix())
                    {
                        throw new SOAPException("Invalid WS-I Basic Profice 1.2 SOAP Envelope \"" + xml.getName() + "\". " + ERROR_MESSAGE_R1014);
                    }
                    
                    if (SOAPHeader.FQN.equals(eName))
                    {
                        env.header = SOAPHeader.toSOAPHeader(element);
                        env.addChild(element);
                    } else if (SOAPBody.FQN.equals(eName))
                    {
                        if (env.body == null)
                        {
                            env.body = SOAPBody.toSOAPBody(element);
                            env.addChild(element);
                        } else
                        {
                            throw new SOAPException("Invalid WS-I Basic Profice 1.2 SOAP Envelope \"" + xml.getName() + "\". " + ERROR_MESSAGE_R9981);
                        }
                    } else
                    {
                        env.addChild(element);
                    }
                }
            } else
            {
                throw new SOAPException("Invalid WS-I Basic Profice 1.2 SOAP Envelope \"" + xml.getName() + "\". " + ERROR_MESSAGE_R9981);
            }
        } else
        {
            throw new SOAPException("Invalid WS-I Basic Profice 1.2 SOAP Envelope \"" + xml.getName() + "\".  Must be of type \"" + FQN + "\"");
        }
        
        return env;
    }
}
